checkpoint new gpx reader based on QXmlStreamReader instead of expat.
authortsteven4 <tsteven4@f51c46e8-681c-474f-0cfe-069cfd0219fb>
Sat, 24 Aug 2013 01:51:54 +0000 (01:51 +0000)
committertsteven4 <tsteven4@f51c46e8-681c-474f-0cfe-069cfd0219fb>
Sat, 24 Aug 2013 01:51:54 +0000 (01:51 +0000)
the new gpx reader is disabled.

git-svn-id: http://gpsbabel.googlecode.com/svn/trunk@4562 f51c46e8-681c-474f-0cfe-069cfd0219fb

gpsbabel/gpx.cc

index b9aa5818be99f9bdd5110552b961ba4f9dfdd63c..129c78ca358e056811a82ef47329dfac785547aa 100644 (file)
 #include "cet_util.h"
 #include "garmin_fs.h"
 #include <math.h>
-#if HAVE_LIBEXPAT
+#if HAVE_LIBEXPAT && !defined(NEW_GPX_READER)
 #include <expat.h>
 static XML_Parser psr;
+#else
+#include <QtCore/QXmlStreamReader>
+static QXmlStreamReader* reader;
 #endif
 #include "src/core/file.h"
 #include "src/core/xmlstreamwriter.h"
@@ -52,7 +55,11 @@ static QString current_tag;
 static waypoint* wpt_tmp;
 static UrlLink* link_;
 static int cache_descr_is_html;
+#ifndef NEW_GPX_READER
 static gbfile* fd;
+#else
+static gpsbabel::File* iqfile;
+#endif
 static gpsbabel::File* oqfile;
 static gpsbabel::XmlStreamWriter* writer;
 static short_handle mkshort_handle;
@@ -459,6 +466,7 @@ prescan_tags(void)
   }
 }
 
+#ifndef NEW_GPX_READER
 static void
 tag_gpx(const char** attrv)
 {
@@ -485,7 +493,43 @@ tag_gpx(const char** attrv)
     }
   }
 }
+#else
+static void
+tag_gpx(const QXmlStreamAttributes& attr)
+{
+  if (attr.hasAttribute("version")) {
+    /* Set the default output version to the highest input
+     * version.
+     */
+    if (! gpx_version) {
+      gpx_version = xstrdup(CSTR(attr.value("version").toString()));
+    } else if ((strtod(gpx_version, NULL) * 10) < (attr.value("version").toString().toDouble() * 10)) {
+      xfree(gpx_version);
+      gpx_version = xstrdup(CSTR(attr.value("version").toString()));
+    }
+  }
+  if (attr.hasAttribute("src")) {
+    /* TODO: this is unused */
+    /* FIXME: this data may be deallocated */
+    gpx_creator = CSTR(attr.value("src").toString());
+  }
+  /* save namespace declarations in case we pass through elements
+   * that use them to the writer.
+   */
+  const QXmlStreamNamespaceDeclarations ns = reader->namespaceDeclarations();
+  for (int i = 0; i < ns.size(); ++i) {
+    QString prefix = ns[i].prefix().toString();
+    QString namespaceUri = ns[i].namespaceUri().toString();
+    if (!prefix.isEmpty() && (0 != prefix.compare("xsi"))) {
+      if (! gpx_namespace_attribute.hasAttribute(prefix)) {
+        gpx_namespace_attribute.append(prefix.prepend("xmlns:"), namespaceUri);
+      }
+    }
+  }
+}
+#endif
 
+#ifndef NEW_GPX_READER
 static void
 tag_wpt(const char** attrv)
 {
@@ -507,7 +551,25 @@ tag_wpt(const char** attrv)
   }
   fs_ptr = &wpt_tmp->fs;
 }
+#else
+static void
+tag_wpt(const QXmlStreamAttributes& attr)
+{
+  wpt_tmp = waypt_new();
+  link_ = new UrlLink;
+
+  cur_tag = NULL;
+  if (attr.hasAttribute("lat")) {
+    wpt_tmp->latitude = attr.value("lat").toString().toDouble();
+  }
+  if (attr.hasAttribute("lon")) {
+    wpt_tmp->longitude = attr.value("lon").toString().toDouble();
+  }
+  fs_ptr = &wpt_tmp->fs;
+}
+#endif
 
+#ifndef NEW_GPX_READER
 static void
 tag_cache_desc(const char** attrv)
 {
@@ -522,7 +584,20 @@ tag_cache_desc(const char** attrv)
     }
   }
 }
+#else
+static void
+tag_cache_desc(const QXmlStreamAttributes& attr)
+{
+  cache_descr_is_html = 0;
+  if (attr.hasAttribute("html")) {
+    if (attr.value("html").toString().compare("True") == 0) {
+      cache_descr_is_html = 1;
+    }
+  }
+}
+#endif
 
+#ifndef NEW_GPX_READER
 static void
 tag_gs_cache(const char** attrv)
 {
@@ -547,8 +622,34 @@ tag_gs_cache(const char** attrv)
     }
   }
 }
+#else
+static void
+tag_gs_cache(const QXmlStreamAttributes& attr)
+{
+  geocache_data* gc_data = waypt_alloc_gc_data(wpt_tmp);
+
+  if (attr.hasAttribute("id")) {
+    gc_data->id = attr.value("id").toString().toInt();
+  }
+  if (attr.hasAttribute("available")) {
+    if (attr.value("available").toString().compare("True", Qt::CaseInsensitive) == 0) {
+      gc_data->is_available = status_true;
+    } else if (attr.value("available").toString().compare("False", Qt::CaseInsensitive) == 0) {
+      gc_data->is_available = status_false;
+    }
+  }
+  if (attr.hasAttribute("archived")) {
+    if (attr.value("archived").toString().compare("True", Qt::CaseInsensitive) == 0) {
+      gc_data->is_archived = status_true;
+    } else if (attr.value("archived").toString().compare("False", Qt::CaseInsensitive) == 0) {
+      gc_data->is_archived = status_false;
+    }
+  }
+}
+#endif
 
 static void
+#ifndef NEW_GPX_READER
 start_something_else(const char* el, const char** attrv)
 {
   const char** avp = attrv;
@@ -580,6 +681,32 @@ start_something_else(const char* el, const char** attrv)
     avp++;
   }
   *avcp = NULL;
+#else
+start_something_else(const QString el, const QXmlStreamAttributes& attr)
+{
+  char** avcp;
+  int attr_count;
+  xml_tag* new_tag;
+  fs_xml* fs_gpx;
+
+  if (!fs_ptr) {
+    return;
+  }
+
+  new_tag = (xml_tag*)xcalloc(sizeof(xml_tag),1);
+  new_tag->tagname = xstrdup(CSTR(el));
+
+  attr_count = attr.size();
+  new_tag->attributes = (char**)xcalloc(sizeof(char*),2*attr_count+1);
+  avcp = new_tag->attributes;
+  for (int i = 0; i < attr_count; i++)  {
+    *avcp = xstrdup(CSTR(attr[i].name().toString()));
+    avcp++;
+    *avcp = xstrdup(CSTR(attr[i].value().toString()));
+    avcp++;
+  }
+  *avcp = NULL; // this indicates the end of the attribute name value pairs.
+#endif
 
   if (cur_tag) {
     if (cur_tag->child) {
@@ -621,6 +748,7 @@ end_something_else()
   }
 }
 
+#ifndef NEW_GPX_READER
 static void
 tag_log_wpt(const char** attrv)
 {
@@ -657,16 +785,53 @@ tag_log_wpt(const char** attrv)
     waypt_add(lwp_tmp);
   }
 }
+#else
+static void
+tag_log_wpt(const QXmlStreamAttributes& attr)
+{
+  /* create a new waypoint */
+  waypoint* lwp_tmp = waypt_new();
+
+  /* extract the lat/lon attributes */
+  if (attr.hasAttribute("lat")) {
+    lwp_tmp->latitude = attr.value("lat").toString().toDouble();
+  }
+  if (attr.hasAttribute("lon")) {
+    lwp_tmp->longitude = attr.value("lon").toString().toDouble();
+  }
+  /* Make a new shortname.  Since this is a groundspeak extension,
+    we assume that GCBLAH is the current shortname format and that
+    wpt_tmp refers to the currently parsed waypoint. Unfortunatley,
+    we need to keep track of log_wpt counts so we don't collide with
+    dupe shortnames.
+  */
+
+  if ((wpt_tmp->shortname) && (strlen(wpt_tmp->shortname) > 2)) {
+    /* copy of the shortname */
+    lwp_tmp->shortname = (char*) xcalloc(7, 1);
+    sprintf(lwp_tmp->shortname, "%-4.4s%02d",
+            &wpt_tmp->shortname[2], logpoint_ct++);
+
+    waypt_add(lwp_tmp);
+  }
+}
+#endif
 
 static void
+#ifndef NEW_GPX_READER
 gpx_start(void* data, const XML_Char* xml_el, const XML_Char** xml_attr)
+#else
+gpx_start(const QString& el, const QXmlStreamAttributes& attr)
+#endif
 {
   int passthrough;
   int tag;
+#ifndef NEW_GPX_READER
   const char* el = xml_convert_to_char_string(xml_el);
   const char** attr = xml_convert_attrs_to_char_string(xml_attr);
   current_tag.append("/");
   current_tag.append(el);
+#endif
 
 
   /*
@@ -683,9 +848,15 @@ gpx_start(void* data, const XML_Char* xml_el, const XML_Char** xml_attr)
     tag_wpt(attr);
     break;
   case tt_wpt_link:
+#ifndef NEW_GPX_READER
     if (attr[0] && attr[1] && 0 == strcmp(attr[0], "href")) {
       link_url = xstrdup(attr[1]);
     }
+#else
+    if (attr.hasAttribute("href")) {
+      link_url = xstrdup(CSTR(attr.value("href").toString()));
+    }
+#endif
     break;
   case tt_rte:
     rte_head = route_head_alloc();
@@ -723,17 +894,25 @@ gpx_start(void* data, const XML_Char* xml_el, const XML_Char** xml_attr)
     tag_cache_desc(attr);
     break;
   case tt_cache_placer:
+#ifndef NEW_GPX_READER
     if (*attr && (0 == strcmp(attr[0], "id"))) {
       waypt_alloc_gc_data(wpt_tmp)->placer_id = atoi(attr[1]);
     }
+#else
+    if (attr.hasAttribute("id")) {
+      waypt_alloc_gc_data(wpt_tmp)->placer_id = attr.value("id").toString().toInt();
+    }
+#endif
   default:
     break;
   }
   if (passthrough) {
     start_something_else(el, attr);
   }
+#ifndef NEW_GPX_READER
   xml_free_converted_string(el);
   xml_free_converted_attrs(attr);
+#endif
 }
 
 struct
@@ -906,9 +1085,15 @@ xml_parse_time(const QString& dateTimeString)
 }
 
 static void
+#ifndef NEW_GPX_READER
 gpx_end(void* data, const XML_Char* xml_el)
+#else
+gpx_end(const QString& el)
+#endif
 {
+#ifndef NEW_GPX_READER
   const char* el = xml_convert_to_char_string(xml_el);
+#endif
   int pos = current_tag.lastIndexOf('/');
   QString s = current_tag.mid(pos + 1);
   float x;
@@ -918,7 +1103,12 @@ gpx_end(void* data, const XML_Char* xml_el)
   tag_type tag;
 
   if (s.compare(el)) {
+#ifndef NEW_GPX_READER
     fprintf(stderr, "Mismatched tag %s.  Expected %s\n", el, qPrintable(s));
+#else
+//   TODO: I don't think this is necesary with QXmlStreamReader
+    fprintf(stderr, "Mismatched tag %s.  Expected %s\n", CSTR(el), qPrintable(s));
+#endif
   }
 
   tag = get_tag(current_tag, &passthrough);
@@ -1216,7 +1406,9 @@ gpx_end(void* data, const XML_Char* xml_el)
     break;
   case tt_unknown:
     end_something_else();
+#ifndef NEW_GPX_READER
     current_tag.truncate(pos);
+#endif
     return;
   default:
     break;
@@ -1226,11 +1418,13 @@ gpx_end(void* data, const XML_Char* xml_el)
     end_something_else();
   }
 
+#ifndef NEW_GPX_READER
   current_tag.truncate(pos);
   xml_free_converted_string(el);
+#endif
 }
 
-#if ! HAVE_LIBEXPAT
+#if ! HAVE_LIBEXPAT && !defined(NEW_GPX_READER)
 static void
 gpx_rd_init(const char* fname)
 {
@@ -1245,14 +1439,22 @@ gpx_rd_deinit(void)
 #else /* NO_EXPAT */
 
 static void
+#ifndef NEW_GPX_READER
 gpx_cdata(void* dta, const XML_Char* xml_el, int len)
+#else
+gpx_cdata(const char* s)
+#endif
 {
   char* estr;
   int* cdatalen;
   char** cdata;
   xml_tag* tmp_tag;
   size_t slen = strlen(cdatastr.mem);
+#ifndef NEW_GPX_READER
   const char* s = xml_convert_to_char_string_n(xml_el, &len);
+#else
+  int len = strlen(s);
+#endif
 
   vmem_realloc(&cdatastr,  1 + len + slen);
   estr = ((char*) cdatastr.mem) + slen;
@@ -1281,23 +1483,33 @@ gpx_cdata(void* dta, const XML_Char* xml_el, int len)
   *(estr+len) = '\0';
   *cdatalen += len;
 
+#ifndef NEW_GPX_READER
   xml_free_converted_string(s);
+#endif
 }
 
 static void
 gpx_rd_init(const char* fname)
 {
+#ifndef NEW_GPX_READER
   fd = gbfopen(fname, "r", MYNAME);
+#else
+  iqfile = new gpsbabel::File(fname);
+  iqfile->open(QIODevice::ReadOnly);
+  reader = new QXmlStreamReader(iqfile);
+#endif
 
   current_tag.clear();
 
   prescan_tags();
 
+#ifndef NEW_GPX_READER
   psr = XML_ParserCreate(NULL);
   if (!psr) {
     fatal(MYNAME ": Cannot create XML Parser\n");
   }
   XML_SetUnknownEncodingHandler(psr, cet_lib_expat_UnknownEncodingHandler, NULL);
+#endif
 
   cdatastr = vmem_alloc(1, 0);
   *((char*)cdatastr.mem) = '\0';
@@ -1313,8 +1525,10 @@ gpx_rd_init(const char* fname)
     QUEUE_INIT(&gpx_global->keywords.queue);
   }
 
+#ifndef NEW_GPX_READER
   XML_SetElementHandler(psr, gpx_start, gpx_end);
   XML_SetCharacterDataHandler(psr, gpx_cdata);
+#endif
   fs_ptr = NULL;
 }
 
@@ -1324,11 +1538,19 @@ gpx_rd_deinit(void)
 {
   vmem_free(&cdatastr);
 
+#ifndef NEW_GPX_READER
   if (fd) {
     gbfclose(fd);
   }
   XML_ParserFree(psr);
   psr = NULL;
+#else
+  delete reader;
+  reader = NULL;
+  iqfile->close();
+  delete iqfile;
+  iqfile = NULL;
+#endif
   wpt_tmp = NULL;
   cur_tag = NULL;
 }
@@ -1363,7 +1585,7 @@ gpx_wr_deinit(void)
 void
 gpx_read(void)
 {
-#if HAVE_LIBEXPAT
+#if HAVE_LIBEXPAT && !defined(NEW_GPX_READER)
   int len;
   char* buf = (char*) xmalloc(MY_CBUF_SZ);
 
@@ -1375,7 +1597,45 @@ gpx_read(void)
     }
   }
   xfree(buf);
-#endif /* HAVE_LIBEXPAT */
+#else
+  while (!reader->atEnd())  {
+    reader->readNext();
+    // do processing
+    switch (reader->tokenType()) {
+    case QXmlStreamReader::StartElement:
+      current_tag.append("/");
+      current_tag.append(reader->qualifiedName());
+
+      {
+        const QXmlStreamAttributes attrs = reader->attributes();
+        gpx_start(reader->qualifiedName().toString(), attrs);
+      }
+      break;
+
+    case QXmlStreamReader::EndElement:
+      gpx_end(reader->qualifiedName().toString());
+      current_tag.chop(reader->qualifiedName().length() + 1);
+      break;
+
+    case QXmlStreamReader::Characters:
+//    It is tempting to skip this if reader->isWhitespace().
+//    That would lose all whitespace element values if the exist,
+//    but it would skip line endings and indentation that doesn't matter.
+      gpx_cdata(CSTR(reader->text().toString()));
+      break;
+
+    default:
+      break;
+    }
+  }
+  if (reader->hasError())  {
+    fatal(MYNAME ":Read error: %s (%s, line %ld, col %ld)\n",
+          CSTR(reader->errorString()),
+          CSTR(iqfile->fileName()),
+          (long) reader->lineNumber(),
+          (long) reader->columnNumber());
+  }
+#endif /* USE_LIBEXPAT */
 }
 
 static void